﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using SharePoint.Orm.Helpers;
namespace SharePoint.Orm.SiteBuilders {
    ///<summary>
    /// Runs all the builders inside of a building class.
    ///</summary>
    public class BuilderContext : IDisposable {
        ///<summary>
        /// Creates a new instance of the builder context.
        ///</summary>
        ///<param name="ctx"></param>
        ///<param name="siteFieldBuilder"></param>
        ///<param name="buildingClassContainer"></param>
        /// <param name="groupName"></param>
        ///<returns></returns>
        public static BuilderContext CreateBuilderContext(SPDataContext ctx, IFieldBuilder siteFieldBuilder, IBuildingContainer buildingClassContainer,string groupName) {
            return new BuilderContext { BuildingClassContainer = buildingClassContainer, Ctx = ctx, SiteFieldBuilder = siteFieldBuilder, GroupName = groupName};
        }

        private BuilderContext() {

        }
        ///<summary>
        /// The container of all the fields for the site.
        ///</summary>
        public IFieldBuilder SiteFieldBuilder { get; set; }
        ///<summary>
        /// The context of the site.
        ///</summary>
        public SPDataContext Ctx { get; set; }
        ///<summary>
        /// The container of the entities that will be built.
        ///</summary>
        public IBuildingContainer BuildingClassContainer { get; set; }
        ///<summary>
        /// The group name of the entities to be built.
        ///</summary>
        public string GroupName { get; set; }

        public void Dispose() {
            Ctx = null;
        }
        protected IEnumerable<PropertyInfo> GetAllBuilders() {
            if (BuildingClassContainer == null) BuildingClassContainer = (IBuildingContainer)new object();
            PropertyInfo[] allProperties = BuildingClassContainer.GetType().GetProperties();
            return allProperties.Where( p => p.PropertyType.IsDescendantOf(typeof (EntityBuilderBase)));
        }
        ///<summary>
        /// Instantiates all of the builders in the Building Class Container.
        ///</summary>
        public void InstantiateBuilders() {
            IEnumerable<PropertyInfo> builders = GetAllBuilders();
            foreach (PropertyInfo builder in builders) {
                object instance = Activator.CreateInstance(builder.PropertyType, this);
                builder.SetValue(BuildingClassContainer, instance, null);
                PropertyInfo groupProperty = builder.PropertyType.GetProperty("GroupName", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
                groupProperty.SetValue(instance, GroupName, null);
            }
        }
        /// <summary>
        /// Calls the build method on all of the classes in the Building Class Container.
        /// </summary>
        public void RunBuilders() {
            IEnumerable<PropertyInfo> builders = GetAllBuilders();
            foreach (PropertyInfo builder in builders) {
                MethodInfo buildMethod = builder.PropertyType.GetMethod("Build");
                buildMethod.Invoke(builder.GetValue(BuildingClassContainer, null), null);
            }
        }
        internal void RefreshContext() {
            var newCtx = new SPDataContext(Ctx.Url);
            Ctx.Dispose();
            Ctx = newCtx;
        }
    }
}
